using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace HpcClusterControllerLinux
{
    public enum JobState
    {
        Completed,
        Exiting,
        Held,
        Queued,
        Running,
        Transfered,
        Waiting,
        Susppend,
		Unknown
    }

	public class JobLinux
	{
		public int jobid, nds;
		public string username, queue, jobName;
		public JobState state;
        public List<string> allocatedNodes;
		
		/// <summary>
		/// This class holds the cluster job attributes as number of requested nodes, tasks and memory.
		/// </summary>
		/// <param name="jobid">
		/// A <see cref="System.Int32"/>
		/// </param>
		public JobLinux (int jobid)
		{
			this.jobid = jobid;
			parseQstat();
		}

        public JobLinux(string jobid_str)
        {
            this.jobid = Int32.Parse(jobid_str);
            parseQstat();
        }
		
		/// <summary>
		/// get the job attributes using the qstat command
		/// </summary>
		public void parseQstat()
		{
            string stat = Shell.run("qstat", String.Format("-x {0}", jobid));	

			XElement root = XElement.Load(XmlReader.Create(new StringReader(stat)));
			XElement job = root.Element("Job");
			
			this.jobName = job.Element("Job_Name").Value;
			this.nds = int.Parse(job.Element("Resource_List").Element("nodect").Value);
			
			this.username = job.Element("Job_Owner").Value;
			this.queue = job.Element("queue").Value;
			
			switch(job.Element("job_state").Value)
			{
			case "C":
				state = JobState.Completed;
				break;
			case "E":
				state = JobState.Exiting;
				break;	
			case "H":
				state = JobState.Held;
				break;
			case "Q":
				state = JobState.Queued;
				break;
			case "R":
				state = JobState.Running;
				break;
			case "T":
				state = JobState.Transfered;
				break;
			case "W":
				state = JobState.Waiting;
				break;
			case "S":
				state = JobState.Susppend;
				break;
			}
			
			XElement exec_host = job.Element("exec_host");
			if (exec_host != null) {
				string hosts = exec_host.Value;  // something like "linuxnode03.linux/0+linuxnode02.linux/0+linuxnode01.linux/0"
				string[] hostlist = hosts.Split(new char[] {'/', '0', '+'}, StringSplitOptions.RemoveEmptyEntries);
				this.allocatedNodes = new List<string>(hostlist);
			}
			
		}
		
		/// <summary>
		/// Choose the *smallest* job.nodect in the queue
		/// </summary>
		public static int GetSmallestJob()
		{
			string stat = Shell.run("qstat", "-x");	
			
			if (stat == "") { // qstat didn't find any job -> the queue is empty
				return int.MaxValue;
			}
			
			XElement root = XElement.Load(XmlReader.Create(new StringReader(stat)));
			
			var query = (from job in root.Elements("Job") 
			        	let x = int.Parse(job.Element("Resource_List").Element("nodect").Value)
			        	select x);
			
			return query.Min();
		}
	}
}
